﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Nirvana
{
    /// <summary>
    /// 事件点击列表，在lua代码中，脚本无法直接在面板上指定onclick等事件，因此需要此脚本来代替
    /// 指定事件引用
    /// </summary>
    [AddComponentMenu("Nirvana/UI/Bind/UI Event Table")]
    public sealed class UIEventTable : MonoBehaviour
    {
        private static Logger logger = LogSystem.GetLogger("UIEventTable");
        [Tooltip("The event list.")]
        [SerializeField]
        private string[] events;
        /// <summary>
        /// eventname:callback
        /// </summary>
        private Dictionary<string, SignalEvent> signaleventmap;
        /// <summary>
        /// eventname:执行此事件的对象组(脚本)
        /// </summary>
        private Dictionary<string, LinkedList<Component>> componentlist = new Dictionary<string, LinkedList<Component>>(StringComparer.Ordinal);

        public string[] Events
        {
            get
            {
                return this.events;
            }
        }


        private Dictionary<string, SignalEvent> GetSignalEventMap()
        {
            if (this.signaleventmap == null)
            {
                this.signaleventmap = new Dictionary<string, SignalEvent>(StringComparer.Ordinal);
                foreach (string key in this.events)
                {
                    if (!this.signaleventmap.ContainsKey(key))
                    {
                        this.signaleventmap.Add(key, new SignalEvent());
                    }
                }
            }
            return this.signaleventmap;
        }

        public void Sort()
        {
            Array.Sort<string>(this.events);
        }

        public LinkedList<Component> FindReferenced(string eventName)
        {
            if (string.IsNullOrEmpty(eventName))
            {
                return null;
            }
            LinkedList<Component> result;
            if (!this.componentlist.TryGetValue(eventName, out result))
            {
                return null;
            }
            return result;
        }
        /// <summary>
        /// 需在脚本主动添加监听的事件，bindevent才能有效回调
        /// </summary>
        public SignalHandle ListenEvent(string eventName, SignalDelegate callback)
        {
            SignalEvent _event;
            if (!this.GetSignalEventMap().TryGetValue(eventName, out _event))
            {
                logger.LogWarning("{0} is trying to listen event {1}, but it does not existed.", base.name, eventName);
                return new SignalHandle(null, null);
            }
            return _event.Create(callback);
        }

        public void ClearEvent(string eventName)
        {
            SignalEvent _event;
            if (!this.GetSignalEventMap().TryGetValue(eventName, out _event))
            {
                logger.LogWarning("{0} is trying to clear event {1}, but it does not existed.", base.name, eventName);
                return;
            }
            if (_event != null)
            {
                _event.Clear();
            }
        }

        public void ClearAllEvents()
        {
            foreach (var p in this.GetSignalEventMap())
            {
                p.Value.Clear();
            }
        }


        public LinkedListNode<Component> AddComp(string eventName, Component com)
        {
            LinkedList<Component> linkedList;
            if (!this.componentlist.TryGetValue(eventName, out linkedList))
            {
                linkedList = new LinkedList<Component>();
                this.componentlist.Add(eventName, linkedList);
            }
            return linkedList.AddLast(com);
        }
        public void RemoveComp(string eventName, LinkedListNode<Component> coms)
        {
            LinkedList<Component> linkedList;
            if (this.componentlist.TryGetValue(eventName, out linkedList))
            {
                linkedList.Remove(coms);
            }
        }

        public SignalEvent GetSignalEvent(string eventName)
        {
            if (string.IsNullOrEmpty(eventName))
            {
                return null;
            }
            SignalEvent result;
            if (!this.GetSignalEventMap().TryGetValue(eventName, out result))
            {
                return null;
            }
            return result;
        }
    }
}

